home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / xlisp.lbr / XLKMAP.CQ / xlkmap.c
Text File  |  1985-06-03  |  9KB  |  297 lines

  1.                      /* xlkmap - xlisp key map functions */
  2.  
  3. #ifdef CI_86
  4. #include "a:stdio.h"
  5. #include "xlisp.h"
  6. #endif
  7.  
  8. #ifdef AZTEC
  9. #include "a:stdio.h"
  10. #include "xlisp.h"
  11. #endif
  12.  
  13. #ifdef unix
  14. #include <stdio.h>
  15. #include <xlisp.h>
  16. #endif
  17.  
  18.  
  19.                             /* external variables */
  20.  
  21. extern struct node *xlstack;
  22. extern struct node *xlenv;
  23. extern struct node *self;
  24.  
  25.  
  26.                              /* local definitions */
  27.  
  28. #define KMSIZE  256     /* number of characters in a keymap */
  29. #define KMAX    20      /* maximum number of characters in a key sequence */
  30. #define KEYMAP  0       /* instance variable number for 'keymap' */
  31.  
  32.  
  33.                               /* local variables */
  34.  
  35. static struct node *currentenv;
  36.  
  37.  
  38.         /* forward declarations (the extern hack is because of decusc) */
  39.  
  40. extern struct node *sendmsg();
  41.  
  42.  
  43.                       /************************************
  44.                       *  isnew - initialize a new keymap  *
  45.                       ************************************/
  46.  
  47. static struct node *isnew(args)
  48.   struct node *args;
  49. {
  50.     xllastarg(args);                   /* No arguments ! */
  51.  
  52.                                        /* Create a keymap node */
  53.     xlivar(self->n_symvalue,KEYMAP)->n_listvalue = newnode(KMAP);
  54.  
  55.     return (self->n_symvalue);         /* and return it */
  56. }
  57.  
  58.  
  59.             /*******************************************************
  60.             *  newkmap - allocate memory for a new key map vector  *
  61.             *******************************************************/
  62.  
  63. static struct node *(*newkmap())[]
  64. {
  65.     struct node *(*map)[];
  66.  
  67.                                        /* allocate the vector */
  68.     if ((map = (struct node *(*)[]) calloc(1,sizeof(struct node *) * KMSIZE))
  69.                          == NULL)
  70.     {
  71.         printf("insufficient memory");
  72.         exit();
  73.     }
  74.  
  75.     return (map);                      /* And return it */
  76. }
  77.  
  78.  
  79.                             /***********************
  80.                             *  key - define a key  *
  81.                             ***********************/
  82.  
  83. static struct node *key(args)
  84.   struct node *args;
  85. {
  86.     struct node *oldstk,arg,kstr,ksym,*kmap,*kmptr;
  87.     struct node *(*map)[];
  88.     char *sptr;
  89.     int ch;
  90.  
  91.     oldstk = xlsave(&arg,&kstr,&ksym,NULL); /* Create new stack frame */
  92.     arg.n_ptr = args;                       /* initialize */
  93.  
  94.     kmap = xlivar(self->n_symvalue,KEYMAP)->n_listvalue;   /* get keymap */
  95.     if (kmap == NULL && kmap->n_type != KMAP)
  96.         xlfail("bad keymap object");
  97.  
  98.     kstr.n_ptr = xlevmatch(STR,&arg.n_ptr); /* Find key string */
  99.     ksym.n_ptr = xlevmatch(SYM,&arg.n_ptr); /* the the key symbol */
  100.     xllastarg(arg.n_ptr);                   /* and make sure thats all */
  101.  
  102.     for (kmptr = kmap, sptr = kstr.n_ptr->n_str; /* process each char */
  103.          *sptr != 0;
  104.          kmptr = (*map)[ch])
  105.     {
  106.         ch = *sptr++;                       /* Get the character */
  107.         if ((map = kmptr->n_kmap) == NULL)  /* Allocate key map if reqd */
  108.             map = kmptr->n_kmap = newkmap();
  109.  
  110.         if (*sptr == 0)                     /* End of string ? */
  111.             (*map)[ch] = ksym.n_ptr;
  112.         else
  113.             if ((*map)[ch] == NULL || (*map)[ch]->n_type != KMAP)
  114.             {
  115.                 (*map)[ch] = newnode(KMAP);
  116.                 (*map)[ch]->n_kmap = newkmap();
  117.             }
  118.     }
  119.  
  120.     xlstack = oldstk;                       /* Restore old stack frame */
  121.     return (self->n_symvalue);              /* and return keymap */
  122. }
  123.  
  124.  
  125.             /*******************************************************
  126.             *  process - process input characters using a key map  *
  127.             *******************************************************/
  128.  
  129. static struct node *process(args)
  130.   struct node *args;
  131. {
  132.     struct node *oldstk,arg,env,margs,*kmap,*kmptr,*nptr,*oldenv;
  133.     struct node *(*map)[];
  134.     char keys[KMAX+1];
  135.     int ch,kndx;
  136.  
  137.     oldstk = xlsave(&arg,&env,&margs,NULL); /* create new stack frame */
  138.     arg.n_ptr = args;                       /* Initialize */
  139.  
  140.     kmap = xlivar(self->n_symvalue,KEYMAP)->n_listvalue;   /* Get keymap */
  141.     if (kmap == NULL && kmap->n_type != KMAP)
  142.         xlfail("bad keymap object");
  143.  
  144.     env.n_ptr = xlevmatch(LIST,&arg.n_ptr); /* Get the environment */
  145.     xllastarg(arg.n_ptr);                   /* Ensure thats all */
  146.  
  147.     oldenv = xlenv;                         /* Bind the environment variable */
  148.     xlbind(currentenv,env.n_ptr);
  149.     xlfixbindings(oldenv);
  150.  
  151.     if (kmap->n_kmap == NULL)               /* Ensure key map is defined */
  152.         xlfail("empty keymap");
  153.  
  154.     margs.n_ptr = newnode(LIST);            /* Create argument list */
  155.     margs.n_ptr->n_listvalue = newnode(STR);
  156.     margs.n_ptr->n_listvalue->n_str = keys;
  157.     margs.n_ptr->n_listvalue->n_strtype = STATIC;
  158.  
  159.     for (kmptr = kmap, kndx = 0; TRUE; )    /* Character processing loop */
  160.     {
  161.         fflush(stdout);                     /* Flush pending output */
  162.  
  163.         if ((ch = kbin()) < 0)              /* Get a character */
  164.             break;
  165.  
  166.         if (kndx < KMAX)                    /* Put it is the key sequence */
  167.             keys[kndx++] = ch;
  168.         else
  169.             xlfail("key sequence too long");
  170.  
  171.         if ((map = kmptr->n_kmap) == NULL)  /* dispatch on character code */
  172.             xlfail("bad keymap");
  173.         else
  174.         if ((nptr = (*map)[ch]) == NULL)
  175.         {
  176.             kmptr = kmap;
  177.             kndx = 0;
  178.         }
  179.         else
  180.         if (nptr->n_type == KMAP)
  181.             kmptr = (*map)[ch];
  182.         else
  183.         if (nptr->n_type == SYM)
  184.         {
  185.             keys[kndx] = 0;
  186.             if (sendmsg(nptr,currentenv->n_symvalue,margs.n_ptr) == NULL)
  187.                 break;
  188.             kmptr = kmap;
  189.             kndx = 0;
  190.         }
  191.         else
  192.             xlfail("bad keymap");
  193.     }
  194.  
  195.     xlunbind(oldenv);                       /* unbind */
  196.     xlstack = oldstk;                       /* Restore old stack frame */
  197.     return (self->n_symvalue);              /* and return keymap object */
  198. }
  199.  
  200.  
  201.             /*******************************************************
  202.             *  sendmsg - send a message given an environment list  *
  203.             *******************************************************/
  204.  
  205. static struct node *sendmsg(msym,env,args)
  206.   struct node *msym,*env,*args;
  207. {
  208.     struct node *eptr,*obj,*msg;
  209.  
  210.     /* look for an object that answers the message */
  211.     for (eptr = env; eptr != NULL; eptr = eptr->n_listnext)
  212.         if ((obj = eptr->n_listvalue) != NULL && obj->n_type == OBJ)
  213.             if ((msg = xlmfind(obj,msym)) != NULL)
  214.                 return (xlxsend(obj,msg,args));
  215.  
  216.     /* return the message if no object answered it */
  217.     return (msym);
  218. }
  219.  
  220.  
  221.                          /*****************************
  222.                          *  xlkmmark - mark a keymap  *
  223.                          *****************************/
  224.  
  225. xlkmmark(km)
  226.   struct node *km;
  227. {
  228.     struct node *(*map)[];
  229.     int i;
  230.  
  231.     km->n_flags |= MARK;               /* Mark the keymap node */
  232.  
  233.     if ((map = km->n_kmap) == NULL)    /* Check for null keymap */
  234.         return;
  235.  
  236.     for (i = 0; i < KMSIZE; i++)       /* Loop through each entry */
  237.         if (((*map)[i] != NULL) && (*map)[i]->n_type == KMAP)
  238.             xlkmmark((*map)[i]);
  239. }
  240.  
  241.  
  242.                          /*****************************
  243.                          *  xlkmfree - free a keymap  *
  244.                          *****************************/
  245.  
  246. xlkmfree(km)
  247.   struct node *km;
  248. {
  249.     struct node *(*map)[];
  250.     int i;
  251.  
  252.     if ((map = km->n_kmap) == NULL)         /* Check for null keymap */
  253.         return;
  254.  
  255.     for (i = 0; i < KMSIZE; i++)            /* loop through each entry */
  256.         if (((*map)[i] != NULL) && (*map)[i]->n_type == KMAP)
  257.             xlkmfree((*map)[i]);
  258.  
  259.     free(km->n_kmap);                       /* and free this one */
  260. }
  261.  
  262.  
  263.              /******************************************************
  264.              *  xlkinit - key map function initialization routine  *
  265.              ******************************************************/
  266.  
  267. xlkinit()
  268. {
  269.     struct node *keymap;
  270.  
  271.     currentenv = xlenter("currentenv");     /* Define xlisp variables */
  272.  
  273.     keymap = xlclass("Keymap",1);           /* Define keymap class */
  274.     xladdivar(keymap,"keymap");
  275.     xladdmsg(keymap,"isnew",isnew);
  276.     xladdmsg(keymap,"key",key);
  277.     xladdmsg(keymap,"process",process);
  278. }
  279.  
  280.  
  281.                          /******************************
  282.                          *  kbin : fetch a key stroke  *
  283.                          ******************************/
  284.  
  285. static kbin()
  286. {
  287. #ifdef AZTEC
  288.     return (CPM(6, 0xFF));
  289. #endif
  290.  
  291. #ifdef CI_86
  292.     if (bdos(0x0b, 0) & 0xFF == 0xFF)
  293.          return (bdos(0x08, 0));
  294.     return -1;
  295. #endif
  296. }
  297.